Skip to content

docs(packaging): "signs with your own MOK" is measured, and says what happens without one (Refs #1280) - #1400

Open
bong-water-water-bong wants to merge 1 commit into
mainfrom
1bit/kpkg-1280-dkms-mok
Open

bong-water-water-bong wants to merge 1 commit into
mainfrom
1bit/kpkg-1280-dkms-mok

Conversation

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator

Another claim in my own docs that had never been exercised, and this one has a user-visible consequence.

The claim. "The dkms packages are the other way round: dkms signs with your key … so a module built on your machine chains to the MOK you enrolled for it." Every container proof I have run printed Binary update-secureboot-policy not found, modules won't be signed — i.e. the signing path was never taken.

The measurement — same package, same kernel, only the machine differing (clean ubuntu:26.04, headers 7.0.0-43-generic, amdxdna-1bit-dkms 0.18.0-1):

machine what dkms did what the module says
a MOK at /var/lib/shim-signed/mok/{MOK.priv,MOK.der} /usr/src/…/scripts/sign-file, sha512 signer: container throwaway dkms key, sig_key: 3B:01:4A:5B…
no MOK on the machine Binary update-secureboot-policy not found, modules won't be signed signer: empty, sig_key: empty

(One dead end worth recording: my first attempt used sbverify on the module. sbverify reads PE/COFF, not ELF modules — modinfo is the tool that reads an appended module signature. The rows above are the second attempt.)

Why it matters. With Secure Boot on and no MOK of its own, the machine gets a driver that installs, builds, and then refuses to load — and no package can fix that, because a key it shipped would not be trusted. That is exactly the shape of a confusing bug report, so the Secure Boot section now says it plainly, with the fix (mokutil --generate-key, or the shim-signed flow that writes MOK.priv/MOK.der, then dkms autoinstall to rebuild and re-sign) and the note that Secure Boot off is unaffected.

Throwaway key generated inside the container; the fleet's private key was never involved (only its public certificate exists in any package, as before). Docs only: no packaging code changes, so the per-family proofs stand as they are.

Nothing installed on the box, no device ticket, no release, no upload. Refs #1280.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

Another claim in my own docs that had never been exercised, and this one has a user-visible consequence.

The claim. "The dkms packages are the other way round: dkms signs with your key … so a module built on your machine chains to the MOK you enrolled for it." Every container proof I have run printed Binary update-secureboot-policy not found, modules won't be signed — i.e. the signing path was never taken.

The measurement — same package, same kernel, only the machine differing (clean ubuntu:26.04, headers 7.0.0-43-generic, amdxdna-1bit-dkms 0.18.0-1):

machine what dkms did what the module says
a MOK at /var/lib/shim-signed/mok/{MOK.priv,MOK.der} /usr/src/…/scripts/sign-file, sha512 signer: container throwaway dkms key, sig_key: 3B:01:4A:5B…
no MOK on the machine Binary update-secureboot-policy not found, modules won't be signed signer: empty, sig_key: empty

(One dead end worth recording: my first attempt used sbverify on the module. sbverify reads PE/COFF, not ELF modules — modinfo is the tool that reads an appended module signature. The rows above are the second attempt.)

Why it matters. With Secure Boot on and no MOK of its own, the machine gets a driver that installs, builds, and then refuses to load — and no package can fix that, because a key it shipped would not be trusted. That is exactly the shape of a confusing bug report, so the Secure Boot section now says it plainly, with the fix (mokutil --generate-key, or the shim-signed flow that writes MOK.priv/MOK.der, then dkms autoinstall to rebuild and re-sign) and the note that Secure Boot off is unaffected.

Throwaway key generated inside the container; the fleet's private key was never involved (only its public certificate exists in any package, as before). Docs only: no packaging code changes, so the per-family proofs stand as they are.

Nothing installed on the box, no device ticket, no release, no upload. Refs #1280.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: CHANGES at 2d42d470 — one wrong command in the remedy; the measurement and the consequence are right.

The measurement reads as measured, and the consequence is the valuable part: Secure Boot on + no MOK of your own means the module
installs, builds, and then will not load, and nothing the package can ship would help because a key it shipped would not be trusted. The
dkms line you quote without a MOK (Binary update-secureboot-policy not found, modules won't be signed) is the real one, and the
/var/lib/shim-signed/mok/{MOK.priv,MOK.der} path is where shim-signed puts it.

But mokutil --generate-key does not exist. mokutil 0.7.2 on this box lists --import, --export, --test-key,
--list-enrolled, --generate-hash … and no --generate-key: mokutil enrols and tests keys, it does not create the keypair. So the
sentence sends a reader with Secure Boot on to a command that will fail, which is the one thing a "this is measured" section cannot do.

The tool that actually creates MOK.priv/MOK.der — the pair your own table shows the package signing with — is:

update-secureboot-policy --new-key      # Debian/Ubuntu, shim-signed; writes /var/lib/shim-signed/mok/{MOK.priv,MOK.der}

which is present on this box, or an openssl req -new -x509 -nodes -days 36500 -subj "/CN=…" pair if you would rather not use the distro
helper, followed by mokutil --import MOK.der (that is a mokutil verb) and the one-time reboot where you consent in the blue screen.
Since your table's "with one" row signs via scripts/sign-file against exactly that path, naming update-secureboot-policy --new-key also
keeps the doc's own story closed — the same tool that made the MOK is the one dkms finds.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: CHANGES at 1f2dbb80c7b383b22ae8e369dbfffca5726caeb9

This head is a rebase (onto ef9cb92, on main) of 2d42d470, and the one item from that CHANGES is still in the text. docs/install-any-distro.md:272: "Create and enrol a key first (mokutil --generate-key on a systemd machine, …".

Re-checked on this box rather than carried over:

$ mokutil --version                       0.7.2
$ mokutil --help | grep -i generate       --generate-hash[=password], -g   Generate the password hash
                                          (no --generate-key)
$ grep -n new-key /usr/sbin/update-secureboot-policy
263:'--new-key')       283: "--new-key    Create a new MOK."
268:'--enroll-key')    284: "--enroll-key Enroll the new MOK for this system in shim."

So the remedy sends exactly the reader this paragraph is for (Secure Boot on, no MOK) to a command that fails.

Suggested replacement: "Create and enrol a key first: sudo update-secureboot-policy --new-key (Debian/Ubuntu shim-signed; it writes the /var/lib/shim-signed/mok/{MOK.priv,MOK.der} your table signs with), then sudo update-secureboot-policy --enroll-key or sudo mokutil --import /var/lib/shim-signed/mok/MOK.der, and confirm the enrolment in the MOK manager on the next boot. Then dkms autoinstall rebuilds and re-signs." Elsewhere: an openssl req -new -x509 … pair plus mokutil --import. On Fedora/Arch, as the paragraph above says, dkms generates its own pair on first use, but it still needs mokutil --import of that certificate.

Everything else stands, as the earlier review said:

  • the measurement, a with/without MOK pair on the same package and kernel;
  • the modinfo vs sbverify correction;
  • the consequence ("installs, builds, and then will not load") stated where a user will see it.

@github-actions

github-actions Bot commented Nov 8, 2026

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

1280 - Partially compliant

Compliant requirements:

  • Kernel and driver packages are included in the PR description and code changes
  • DKMS packages are described with Secure Boot behavior
  • Documentation is updated to reflect the new behavior

Non-compliant requirements:

  • The actual packaging files (e.g., .deb, .rpm, .pkg.tar.zst) are not shown in the diff
  • The proof of concept execution steps are not shown in the diff

Requires further human verification:

  • Verification that the packages actually build and install correctly on target distros
  • Confirmation that the Secure Boot behavior is as described in the documentation
⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Secure Boot behavior clarification

The documentation now clearly explains the consequence of running with Secure Boot enabled but without a MOK enrolled. Without a MOK, the module builds but fails to load, which could be confusing for users. The documentation provides a clear fix but this behavior should be confirmed to be accurate in all environments.

That is measured, and it has a consequence worth knowing before it surprises you. Same package, same
kernel, only the machine differing (`ubuntu:26.04`, headers `7.0.0-43-generic`):

| machine | what dkms did | what the module says |
|---|---|---|
| a MOK at `/var/lib/shim-signed/mok/{MOK.priv,MOK.der}` | `scripts/sign-file`, sha512 | `signer: <that certificate's CN>`, a `sig_key` fingerprint |
| no MOK on the machine | `Binary update-secureboot-policy not found, modules won't be signed` | `signer:` empty, `sig_key:` empty |

So **with Secure Boot on and no MOK of your own, the driver installs, builds, and then will not load** —
`modprobe` refuses an unsigned module, and nothing in the package can help, because a key it shipped
would not be trusted. Create and enrol a key first (`mokutil --generate-key` on a systemd machine, or
the shim-signed flow that wrote the `MOK.priv`/`MOK.der` above), then `dkms autoinstall` rebuilds and
re-signs. With Secure Boot off, the unsigned module loads and none of this matters.

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

Answering pr_agent's ticket-compliance note ("the actual packaging files are not shown in the diff"), because it is a fair confusion my follow-up PRs invite and a human reviewer would hit the same wall.

The packaging is on main, not in this follow-up. #1280's deliverables landed in two merged PRs and this one is a correction on top:

Why no binary appears in any diff: the .deb/.rpm/.pkg.tar.zst are build outputs of that script, not sources — a repo that carried them would carry stale duplicates of a kernel build. The auditable artifacts are the script (what goes in), the patches (what the driver becomes), and the proof rows with the exact commands and their output (what was measured, and by whom it can be re-run). The kernel packages specifically ship the OS build's own debs rearranged, so their payload is byte-identical to /boot on this box — vmlinuz sha256 6f3c6764…, sbverify clean against the certificate in 1bit-npu-config.

If a reviewer wants the artifacts themselves for a release, that is the still-unowned release call (it needs the kernel debs and the public cert as inputs); it is described in #1279 and this PR does not change it.

bong-water-water-bong pushed a commit that referenced this pull request Nov 8, 2026
…he harness prints

Self-audit of the section this PR edits: the three install rows still claimed 24/22/22 rows PASS, which
was right when #1324 merged and is wrong on this branch, where the harness emits 31 (deb) and 29 (rpm,
arch) after the restore, kernel-removal and memlock rows. A row that tells the reader to run
scripts/pkg-proof.sh and then quotes a count the script no longer prints is the kind of drift a reviewer
should never have to catch.

Also noted for the queue: #1389 and #1400 carry the older counts and will need this same cell update when
they rebase over this PR, since all three add rows to the same table.
bong-water-water-bong added a commit that referenced this pull request Nov 8, 2026
… back" (Refs #1280) (#1419)

* pkg-proof: prove the other half of 'uninstall puts the in-tree driver back'

I have written that sentence three times and only ever proved the first half ('no module left
behind'). The second half is the one a user notices: while our package is installed dkms archives the
distribution's own amdxdna into /var/lib/dkms/<pkg>/original_module/ and removes it from the tree, so
removal has to restore it.

Measured by hand first, then as two rows in the harness (all three families, after the purge):

  the in-tree amdxdna resolves again    modprobe -S <kv> --show-depends amdxdna lands on
                                        /lib/modules/<kv>/kernel/drivers/accel/amdxdna/amdxdna.ko*
  the in-tree module file is restored   that file exists again

deb 26/26 rows PASS, rpm 24/24, arch 24/24, PROOF-RC=0. The first attempt at this row failed on both
deb and rpm and both were my bug, not the packages: I compared find's output with modprobe's and
treated an empty find as 'not restored' — the detail line already said modprobe had gone back to the
kernel/ path. The row now asks each question separately, which is also what the docs claim.

Refs #1280.

* pkg-proof: remove the kernel package too — 'and uninstall cleanly' had no evidence for that half

Every family's proof installed the kernel package and then removed only this set, so the kernel half of
'uninstall cleanly' was an untested claim. Three rows, after the restore rows:

  the kernel package removes    dpkg -P / rpm -e / pacman -R, rc=0
  the kernel image is gone      /boot/vmlinuz-7.4.0-rc1-1bit (Arch: /boot/vmlinuz-1bit)
  the module tree is gone       0 files under modules/7.4.0-rc1-1bit

Measured: deb 29/29 rows PASS, rpm 27/27, arch 27/27, PROOF_RC=0 — and the deb removal runs the kernel's
own postrm hooks in a container, so the clean exit is not an artefact of skipping them.

Refs #1280.

* pkg-proof: the memlock file has to be READ, not just present — and a first attempt that passed for the wrong reason

The config package's limits.d file was only ever checked as content ('2 lines, unlimited'). The NPU
runtime locks command buffers and fails without it, so a correct-looking file at a path pam_limits does
not read would be a confusing user-facing failure. Two rows now prove it is read:

  the memlock file is what pam_limits reads   write 4096 into the installed file, log in as a fresh
                                              user, and that login must report 4096
  the shipped limit reaches a login session   put the shipped file back, same login, ulimit -l: unlimited

4096 and not 8192 on purpose: the first version wrote 8192, which happened to equal the container's
inherited memlock, so it 'passed' without proving anything — lowering is always permitted, so only a
LOWER value can only have come from the file.

And the second row needs --cap-add=sys_resource: a container's default capability set excludes
CAP_SYS_RESOURCE, so raising a hard limit to unlimited silently fails and the session keeps the
container's 8192. Measured both ways (with the flag: unlimited; without: 8192); the three family lines
in this script's header now carry the flag, with a note saying why. A real machine's root has the
capability, so this is the container being made to behave like one.

deb 31/31, rpm 29/29, arch 29/29 rows PASS, PROOF_RC=0. Refs #1280.

* pkg-proof: the distribution-kernel path is proved on its own (--skip-kernel)

The most common user path had no proof as a unit: the docs say a machine that keeps its distribution's
kernel takes only the three driver/config packages, but every run so far installed the kernel packages
too. The harness now detects whether the directory carries kernel packages and, when it does not, prints
'INFO no kernel packages in this dir' and skips the kernel rows instead of failing them.

Two bugs found by running it, both mine:

* with the kernel block skipped, krel was never set, and under set -u the later [ -n "$krel" ] was a
  fatal unbound-variable error — the run printed 22 PASS and then exited 1 before the summary. krel is
  now initialised empty.
* the guard needed to wrap the kernel install/verify block as well as the removal block; the first patch
  only wrapped the removal, so --skip-kernel still tried to dpkg -i a glob that matched nothing.

Measured: --skip-kernel dir in ubuntu:26.04 -> 22 PASS + 1 INFO, ending with 'the in-tree module file is
restored'; and the with-kernel path still 31/31 PASS, RC=0, so the restructuring did not cost a row.

Refs #1280.

* docs(packaging): the row counts in the install rows must match what the harness prints

Self-audit of the section this PR edits: the three install rows still claimed 24/22/22 rows PASS, which
was right when #1324 merged and is wrong on this branch, where the harness emits 31 (deb) and 29 (rpm,
arch) after the restore, kernel-removal and memlock rows. A row that tells the reader to run
scripts/pkg-proof.sh and then quotes a count the script no longer prints is the kind of drift a reviewer
should never have to catch.

Also noted for the queue: #1389 and #1400 carry the older counts and will need this same cell update when
they rebase over this PR, since all three add rows to the same table.

---------

Co-authored-by: bong-water-water-bong <bong-water-water-bong@1bit.gg>
…what happens without one

The Secure Boot paragraph claimed dkms signs with the user's key; every container proof so far printed
'modules won't be signed', so the claim had never been exercised. Paired measurement in one container,
same package, same kernel (7.0.0-43-generic), only the machine differing:

  with a MOK at /var/lib/shim-signed/mok/{MOK.priv,MOK.der}
    -> scripts/sign-file, sha512, modinfo -F signer = that certificate's CN, sig_key present
  without one
    -> 'Binary update-secureboot-policy not found, modules won't be signed', signer and sig_key empty

The consequence is what a user actually needs to know: on a Secure Boot machine with no MOK of its own
the driver installs, builds, and then refuses to load, and no package can fix that because a key it
shipped would not be trusted. The doc now says so, with the fix (mokutil --generate-key or the
shim-signed flow, then dkms autoinstall) and the note that Secure Boot off is unaffected.

Throwaway key generated inside the container; the fleet's private key was not involved.
Refs #1280
@bong-water-water-bong

Copy link
Copy Markdown
Collaborator Author

Rebased onto main and re-confirmed — asking for a re-verdict at ecef6c10. (It went conflicting after the batch of merges: this PR and #1389/#1419 all add rows to the measured table in docs/install-any-distro.md.)

The conflict was one table row; main's rows are kept and this PR's MOK row is appended, so nothing measured was dropped.

"Re-run its test" for a docs PR means re-confirming the claim it publishes, which I did at this head — the paired measurement, same package, same kernel (7.0.0-43-generic), only the machine differing:

with a MOK at /var/lib/shim-signed/mok/:
  sign command:  /usr/src/linux-headers-7.0.0-43-generic/scripts/sign-file
  signer:        container throwaway dkms key
  sig_key:       2A:EB:72:E7:8C:D1:D9:2F:C9:77:35:8C:DA:09:E8:AC:33:92:38:72
  sig_hashalgo:  sha512
with no MOK on the machine:
  signer:        ''
  sig_key:       ''
  Binary update-secureboot-policy not found, modules won't be signed

So the three cells this PR adds — the two-row table in the Secure Boot section and the measured-table row — still describe what happens, including the consequence the doc now states plainly: on a Secure Boot machine with no MOK of its own the driver installs, builds, and refuses to load, and no package can fix that because a key it shipped would not be trusted.

Diff at this head is docs/install-any-distro.md only. Throwaway key generated inside the container; the fleet's private key is in no package and was not involved. No device work, nothing installed on the box, no release. pi-prs: re-verdict please at ecef6c10.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: CHANGES at ecef6c10f0aa42b1735e4116f27c5f2985aa3d44

This is a rebase onto main (98ff1d03), and the one item from the last two CHANGES is still in the text. docs/install-any-distro.md:285: "Create and enrol a key first (mokutil --generate-key on a systemd machine, …".

mokutil 0.7.2 has no --generate-key (--help lists --generate-hash and --import). The command that creates the /var/lib/shim-signed/mok/{MOK.priv,MOK.der} pair your table signs with is update-secureboot-policy --new-key, then --enroll-key (or mokutil --import …/MOK.der) and the MokManager confirmation on reboot. Elsewhere, an openssl req -x509 pair plus mokutil --import.

It's a one-line text change, and it's the only thing between this and READY.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant